/*
    This is a set of libraries to assist in OpenGl and Other Applications
    Copyright (C) 2008  The Modular Engine Team

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
#define CONSOLEMODULE
#include "ConsoleModule.h"

namespace ModularEngine
{

	int ConsoleModule::initialize()
	{
		mfConsole = 0;

		return 1;
	}

	int ConsoleModule::run()
	{
		// Do nothing.

		return 1;
	}

	std::vector<std::string> ConsoleModule::splitCommand( std::string str )
	{
		std::vector<std::string> commands;
		int last = 0;
		bool inQuote = false;
		int j = 0;
		for( int i = 0; i <= str.length(); i++ )
		{

			if( (str[i] == ' ' || i == str.length()) && !inQuote )
			{			
				if( i==last )
					break;
				commands.push_back( str.substr( last, i-last ) );
				j++;
				last = i+1;
			}

			if( str[i] == '\"' || str[i] == '\'' )
			{
				if( inQuote )
				{
					commands.push_back( str.substr( last+1, i-last-1 ) );
					i++;
					last = i;
					j++;
					
				}

				inQuote = !inQuote;
			}


		}

		if( inQuote )
			commands[0] = "ERR_INQUOTE";

		return commands;
	}
#if 0
	CArgType ConsoleModule::parseArgType( std::string str )
	{
		if( (str[0] >= '0' && str[0] <= '9') || str[0] == '-' )
		{
			// Check to make sure all the characters are numbers... or decimals.
			for( int i = 0; i < str.length(); i++ )
			{
				if( !( ( str[i] >= '0' && str[i] <= '9' ) || str[i] == '.' ) )
				{
					return C_STRING;
				}
			}
		}
	}
#endif

	double ConsoleModule::toNumber( std::string str )
	{
		return atof( str.c_str() );
	}

	std::string ConsoleModule::sendCommand( std::string str )
	{
		if( str.length() == 0 )
		{
			console( "Console>> \n  Error:\n  No Commands Given.  Type help help." );
			return "";
		}

		std::vector<std::string> commands = splitCommand( str );
		
		if( commands[0] == "ERR_INQUOTE" )
		{
			console( "Console>> \n  Error:\n  All Strings Must Be Enclosed" );
			return "";
			//return "Console>> Error:\nAll Strings Must Be Enclosed";
		}

		CFunctor *func = 0;
		for( std::vector<CFunctor *>::iterator i = mConsoleFunctions.begin(); i != mConsoleFunctions.end(); i++ )
		{


			if( commands[0] == (*i)->mFuncName )
			{
				func = *i;
			}
		}

		if( !func )
		{
			std::string error;
			error = "Console>> \n  Error:\n  `";
			error += commands[0];
			error += "` is not a valid console function.";
			console( error );
			//ModularEngine::TestModule::getSingleton().tb->addText( error.c_str() );
			
			return "";
			//return error;
		}


		if( func->mArgs.size() != commands.size()-1 )
		{
			console( "Console>> \n  Error:\n  Too many or too few arguments!" );
			return "";
		}

#if 0
		int j = 1;
		for( std::vector<CArg>::iterator i = func->mArgs.begin(); i != func->mArgs.end(); i++, j++ )
		{
			if( i->mArgType != parseArgType( commands[j] ) )
				return "Console>> Error:\nArgument types do not match function.";
		}
#endif

		// Ok by this point if no errors have been returned we can run the command
		for( int i = 1; i < commands.size(); i++ )
		{
			if( func->mArgs[i-1].mArgType == C_STRING )
				func->mArgs[i-1].msArg = commands[i];
			if( func->mArgs[i-1].mArgType == C_NUMBER )
			{
				func->mArgs[i-1].mfArg = toNumber(commands[i]);
			}
		}

		(*func)();
		

		return "";
	}

	void ConsoleModule::addCommand( CFunctor *pFunc )
	{
		mConsoleFunctions.push_back( pFunc );
	}

#ifdef PORTING
	void console( const char *str )
	{
		if( !ConsoleModule::getSingleton().mfConsole )
			std::cout << str << std::endl;
		else
			(*ConsoleModule::getSingleton().mfConsole)((char *)str);

		//	ModularEngine::TestModule::getSingleton().consoleText->addText( str );
	}
#endif



#include <stdio.h>
#include <stdarg.h>

	void console( const char *str, ... )
	{
		va_list argList;
		va_start(argList, str);
		std::string outputVal;
		char *num = new char[64];
		// Basically a printf function w/ the console:
		while( *str != '\0' )
		{
			memset( num, 0, sizeof( char ) * 64 );
			if( *str == '%' )
			{
				*str++;
				switch( *str )
				{
#if 0
					// pointless to have this and the default...
				case 'd':
					{
						sprintf( num, "%d", va_arg(argList, int) );
						outputVal += num;
					} break;
#endif
				case 's':
					{
						outputVal += va_arg(argList, char *);
					} break;
				case 'f':
					{
						float f = va_arg(argList, float);
						sprintf( num, "%f", (float)f );
						outputVal += num;
					} break;
				default:
					{
						sprintf( num, "%d", va_arg(argList, int) );
						outputVal += num;
					} break;

				}

			} else 
				outputVal += *str;

			*str++;

		}

		va_end(argList);

		if( !ConsoleModule::getSingleton().mfConsole )
			std::cout << outputVal.c_str() << std::endl;
		else
			(*ConsoleModule::getSingleton().mfConsole)((char *)outputVal.c_str());

		delete [] num;

	}

	void console( std::string str )
	{

		console( str.c_str() );
	}


}